package com.youcheng.configcenter.dao;

import com.youcheng.configcenter.exception.ConfigCenterServiceException;
import com.youcheng.configcenter.model.ConfigFileDO;
import org.springframework.util.StringUtils;

import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.List;
import java.util.Objects;

/**
 * @author sunhongmin
 * @date 2022/10/21 23:59
 * @description
 */
public class ApplicationConfigDaoImpl implements ApplicationConfigDao {

    private final DataAccessBase dataAccessBase;
    private final static String BASE_COLUMN = "id, file_id, `name`, profile, extension, content, last_updated_time, last_updated_user, version";
    private final static SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
    private final static String DEFAULT_PROFILE = "local";

    public ApplicationConfigDaoImpl(DataAccessBase dataAccessBase) {
        this.dataAccessBase = dataAccessBase;
    }

    @Override
    public void saveConfigFile(ConfigFileDO configFileDO) throws ConfigCenterServiceException {
        // profile
        if (!StringUtils.hasLength(configFileDO.getProfile())) {
            configFileDO.setProfile(DEFAULT_PROFILE);
        }

        // version
        ConfigFileDO configFileLast = this.findConfigFileLast(configFileDO.getFileId(), configFileDO.getProfile());
        if (Objects.nonNull(configFileLast)) {
            Long version = configFileLast.getVersion();
            configFileDO.setVersion(++version);
        } else {
            configFileDO.setVersion(1L);
        }

        String sql = "insert into application_config_center_info (file_id, name, profile, extension, last_updated_time, last_updated_user, version, content) " +
                " values (?, ?, ?, ?, ?, ?, ?, ?)";
        Object[] parameters = {configFileDO.getFileId(), configFileDO.getName(), configFileDO.getProfile(), configFileDO.getExtension(), sdf.format(configFileDO.getLastUpdatedTime()), configFileDO.getLastUpdatedUser(), configFileDO.getVersion(), configFileDO.getContent()};

        PreparedStatement sqlPrepareStatement = null;
        try {
            sqlPrepareStatement = dataAccessBase.getSqlPrepareStatement(sql, parameters);
            sqlPrepareStatement.executeUpdate();
        } catch (SQLException | ClassNotFoundException e) {
            throw new ConfigCenterServiceException(e);
        } finally {
            this.cleseStatement(sqlPrepareStatement);
        }
    }

    @Override
    public ConfigFileDO findConfigFileLast(String fileId, String profile) throws ConfigCenterServiceException {
        if (!StringUtils.hasLength(profile)) {
            profile = DEFAULT_PROFILE;
        }

        String sql = "select " + BASE_COLUMN + " from application_config_center_info where file_id = ? and profile = ? order by version desc limit 1";
        Object[] parameters = {fileId, profile};
        List<ConfigFileDO> queryExcuteResult = this.getQueryExcuteResult(sql, parameters);
        return queryExcuteResult.stream().findFirst().orElse(null);
    }


    @Override
    public ConfigFileDO findConfigFile(String fileId, String profile, Integer version) throws ConfigCenterServiceException {
        if (!StringUtils.hasLength(profile)) {
            profile = DEFAULT_PROFILE;
        }

        String sql = "select " + BASE_COLUMN + " from application_config_center_info where file_id = ? and profile = ? and version = ?";
        Object[] parameters = {fileId, profile, version};
        List<ConfigFileDO> queryExcuteResult = this.getQueryExcuteResult(sql, parameters);
        return queryExcuteResult.stream().findFirst().orElse(null);
    }

    @Override
    public List<ConfigFileDO> listConfigFileHistory(String fileId, String profile) throws ConfigCenterServiceException {
        if (!StringUtils.hasLength(profile)) {
            profile = DEFAULT_PROFILE;
        }

        String sql = "select " + BASE_COLUMN + " from application_config_center_info where file_id = ? and profile = ?";
        Object[] parameters = {fileId, profile};
        return getQueryExcuteResult(sql, parameters);
    }


    private List<ConfigFileDO> getQueryExcuteResult(String sql, Object[] parameters) throws ConfigCenterServiceException {
        PreparedStatement sqlPrepareStatement = null;
        try {
            sqlPrepareStatement = dataAccessBase.getSqlPrepareStatement(sql, parameters);
            try (ResultSet resultSet = sqlPrepareStatement.executeQuery()) {
                return this.configFileDoListAssembler(resultSet);
            }
        } catch (SQLException | ClassNotFoundException e) {
            throw new ConfigCenterServiceException(e);
        } finally {
            this.cleseStatement(sqlPrepareStatement);
        }
    }

    private void cleseStatement(PreparedStatement sqlPrepareStatement) {
        if (Objects.nonNull(sqlPrepareStatement)) {
            try {
                sqlPrepareStatement.close();
            } catch (SQLException ignored) {
            }
        }
        dataAccessBase.closeConnection();
    }

    private List<ConfigFileDO> configFileDoListAssembler(ResultSet resultSet) throws SQLException {
        List<ConfigFileDO> configFileList = new ArrayList<>(32);
        while (resultSet.next()) {
            ConfigFileDO fileDO = new ConfigFileDO();
            fileDO.setId(resultSet.getLong(1));
            fileDO.setFileId(resultSet.getString(2));
            fileDO.setName(resultSet.getString(3));
            fileDO.setProfile(resultSet.getString(4));
            fileDO.setExtension(resultSet.getString(5));
            fileDO.setContent(resultSet.getString(6));
            fileDO.setLastUpdatedTime(resultSet.getTimestamp(7));
            fileDO.setLastUpdatedUser(resultSet.getString(8));
            fileDO.setVersion(resultSet.getLong(9));
            configFileList.add(fileDO);
        }
        return configFileList;
    }
}
